﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Perovich.GameObjects.Interfaces;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Perovich.GameObjects.Components;

namespace Perovich.GameObjects.Entities
{
    public class Entity : EntityComponentCollection, IEntity
    {
        string name;
        Guid guid;
        ICanHoldComponents parent;


        
        /// <summary>
        /// Gets the <see cref="ContentManager"/> for this <see cref="DrawableEntityComponent"/> instance.
        /// </summary>
        public ContentManager Content
        {
            get;
            private set;
        }

        public Entity(string name, ICanHoldComponents parent)
            : this(name, parent, new IEntityComponent[] { }) { }

        public Entity(string name, ICanHoldComponents parent, params IEntityComponent[] components)
            :base(parent)
        {
            this.name = name;

            if (components.Length > 0)
            {
                foreach (IEntityComponent component in components)
                {
                    Add(component);
                }
            }

            parent.Components.Add(this);
            this.parent = parent;
            parent.SpriteBatchSet += new EventHandler<EventArgs>(game_SpriteBatchSet);

            guid = Guid.NewGuid();

            Content = parent.Content;
        }

        void game_SpriteBatchSet(object sender, EventArgs e)
        {
            SBatches = (sender as Interfaces.ICanHoldComponents).SBatches;
        }

        protected override void OnComponentAdded(EntityComponentEventArgs e)
        {
            // can't circumvent doing this.. as using the factory would'nt be good in every thinkable situation
            EntityComponent ec = e.Component as EntityComponent;

            ec.Owner = this;

            base.OnComponentAdded(e);
        }


        public override void Initialize()
        {
            foreach (IEntityComponent c in this)
            {
                c.Initialize();
            }
            base.Initialize();
        }

        protected override void LoadContent()
        {
            foreach (IEntityComponent c in this)
            {
                IHaveContent cont = c as IHaveContent;
                if (cont != null)
                {
                    cont.LoadContent();
                }
            }
            base.LoadContent();
        }

        protected override void UnloadContent()
        {
            foreach (IEntityComponent c in this)
            {
                IHaveContent cont = c as IHaveContent;
                if (cont != null)
                {
                    cont.UnloadContent();
                }
            }
            base.UnloadContent();
        }

        public override void Update(GameTime gameTime)
        {
            var sorted = this.Select(c => c as IUpdateable).Where(u => u != null).OrderBy(u => u.UpdateOrder);
            foreach (IUpdateable u in sorted)
            {
                if (u.Enabled)
                {
                    u.Update(gameTime);
                }
            }
            base.Update(gameTime);
        }

        public override void DrawOnTargets(GameTime gameTime)
        {
            var sorted = this.Select(c => c as IDrawableExt).Where(u => u != null).OrderBy(u => u.DrawOrder);

            foreach (IDrawableExt c in sorted)
            {
                if (c.Visible)
                {
                    c.DrawOnTargets(gameTime);
                }
            }
            base.DrawOnTargets(gameTime);
        }

        public override void Draw(GameTime gameTime)
        {
            var sorted = this.Select(c => c as IDrawableExt).Where(u => u != null).OrderBy(u => u.DrawOrder);

            foreach (IDrawableExt c in sorted)
            {
                if (c.Visible)
                {
                    c.Draw(gameTime);
                }
            }
            base.Draw(gameTime);
        }

        #region IEntity Members

        public ICanHoldComponents Parent
        {
            get
            {
                return parent;
            }
        }


        public string Name
        {
            get
            {
                return name;
            }
        }

        public Guid ID
        {
            get
            {
                return guid;
            }
        }

        
        #endregion

       

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                foreach (IDisposable component in this.Select(c => c as IDisposable).Where(d => d != null))
                {
                    component.Dispose();
                }
            }
            base.Dispose(disposing);
        }

    }
}
